home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.qualcomm.com
/
2014.06.ftp.qualcomm.com.tar
/
ftp.qualcomm.com
/
eudora
/
developers
/
emsapi
/
carbon_emsapi.sit.hqx
/
Macintosh API Support
/
rfc822.c
< prev
next >
Wrap
Text File
|
2001-03-08
|
8KB
|
302 lines
/* =========================================================================
Functions for very basic RFC-822 header manipulation
Filename: rfc822.c
Last Edited: March 7, 1997
Authors: Laurence Lundblade, Myra Callen, Bob Fronabarger
Copyright: 1995, 1996 QUALCOMM Inc.
Technical support: <emsapi-info@qualcomm.com>
Some of this code is from the c-client and is
Copyright University of Washington
*/
#include <string.h>
#include "CopyCat.h"
#include "RFC822.h"
/* All these special characters will confuse CodeWarrior so you may not get
* the colorized comments and key words you are use to.
*/
extern const char *hSpecials = " ()<>@,;:\\\042"; /* parse-host specials (\042 = ") */
extern const char *wSpecials = " ()<>@,;:\\\042[]"; /* parse-word specials */
extern const char *ptSpecials = " ()<>@,;:\\\042[]/?="; /* parse-token specials */
const char *kRFC822_MustBeQuoted = "()<>@,;:\\\042/[]?= ";
const char *kRFC822_MustBeEscaped = "\\\042";
char *RFC822_UnquoteStrCpy(char *dst, const char *src, unsigned int len);
/* =========================================================================
* Find next RFC822 token in given string, copying it into a newly created
* string. Advance pointer past token and any following whitespace.
*
* NOTE: The user of this function is responsible for freeing returned string.
*
* Args: cpp [IN/OUT] Handle (pointer-to-pointer) of RFC822 string to extract from
*
* Returns: String containing next token, nil if error.
* Moves cpp to first non-whitespace character AFTER extracted token
*/
char *RFC822_ExtractToken(char **cpp)
{
char *start, *buf, *cp = *cpp;
short len;
start = cp = RFC822_SkipWS(cp); // Skip white space
cp = RFC822_SkipWord(cp); // Skip word
if (cp > start) {
len = cp - start;
buf = NewPtr(len + 1);
if (buf) {
RFC822_UnquoteStrCpy(buf, start, len);
*cpp = RFC822_SkipWS(cp);
return buf;
}
}
return nil; // No token to extract
}
/* =========================================================================
* Skips RFC822 whitespace
*
* Args: Text string
*
* Returns: Moves cpp to first non-whitespace character
*/
char *RFC822_SkipWS(char *cp)
{
long nested;
do {
while (*cp == ' ') // Skip spaces
cp++;
if (*cp == '(') { // A comment?
nested = 1;
while ((*++cp) && nested) { // Find end of comment
switch (*cp) {
case '(':
nested++;
break;
case ')':
nested--;
break;
case '\\': // Escape character
if ((*(cp + 1)) != '\0') // Check for end-of-string
cp++;
break;
case '"': // Quote inside comment
while (*cp && (*++cp != '"')) // Go 'til end of quote
if ((*cp == '\\') && ((*(cp + 1)) != '\0'))
cp++; // Escaped character inside quote -- inside comment (eeek!)
break;
}
}
}
} while (*cp == ' ');
return cp;
}
/* =========================================================================
* Advances to next character in string directly after the current token.
* The first character must be the beginning of a valid token or end of
* string (ie. all whitespace must be skipped BEFORE calling this function).
*
* Args: cp [IN] RFC822 string
*
* Returns: Pointer to next valid whitespace character.
*/
char *RFC822_SkipWord(char *cp)
{
Boolean bInQuotes = false;
if (*cp == '"') { // First character must be a quote to be valid double-quoted string
bInQuotes = true;
cp++;
}
while (*cp) {
if (strchr(kRFC822_MustBeQuoted, *cp)) {
if (!bInQuotes) // Found a character that should be double-quoted, but is not
return (cp);
switch (*cp) { // Now we know we are inside a double-quoted string
case '"':
return (cp + 1); // End double-quote
case '\\':
cp++; // Escape character, skip next
break;
}
}
cp++;
}
return cp;
}
/* =========================================================================
* Calculates the length of the given text string if it were converted
* to an RFC822 string.
*
* Args: cp [IN] Text string
*
* Returns: Equivalent RFC822 length of given text.
*/
unsigned short RFC822_QuotedStrLen(StringPtr theStr)
{
unsigned short len = 0;
char s[256], *cp; // i know these strings are short
Boolean quoted = false;
BlockMoveData(theStr, s, theStr[0] + 1);
PtoCstr((StringPtr) s);
cp = s;
while (*cp) {
len++;
if (!quoted && (strchr(kRFC822_MustBeQuoted, *cp) != nil))
quoted = true;
if (strchr(kRFC822_MustBeEscaped, *cp) != nil) {
len++;
quoted = true;
}
cp++;
}
if (quoted)
len += 2; // Quotes
return len;
}
/* =========================================================================
* Copies and converts the source text string to a destination
* RFC822 string. The source must be NULL terminated, and the
* destination will be NULL terminated.
*
* Args: dst [OUT] RFC822 string
* src [IN] Text string
*
* Returns: Pointer to destination NULL termination.
*/
char *RFC822_QuoteStrCpy(char *dst, StringPtr theStr)
{
char *src;
Boolean quoted;
PtoCstr(theStr);
src = (char*) theStr;
quoted = (strpbrk(src, kRFC822_MustBeQuoted) != nil);
if (quoted)
*dst++ = '"';
while (*src) {
if (strchr(kRFC822_MustBeEscaped, *src) != nil)
*dst++ = '\\';
*dst++ = *src++;
}
if (quoted)
*dst++ = '"';
*dst = '\0';
CtoPstr((char*) theStr);
return dst;
}
/* =========================================================================
* Copies and converts the source RFC822 string to a destination
* text string. The source must be null terminated, and the
* destination will be null terminated.
*
* Args: dst [OUT] Text string
* src [IN] RFC822 string
* len [IN] Maximum charcters to copy; Zero implies whole string
*
* Returns: Pointer to destination nil termination.
*/
char *RFC822_UnquoteStrCpy(char *dst, const char *src, unsigned int len)
{
char *end;
Boolean escaped = false;
end = strchr(src, '\0');
if ((len > 0) && ((src + len) < end))
end = (char*) src + len;
while (src < end) {
if (escaped)
escaped = false;
else {
switch (*src) {
case '\\':
escaped = true;
case '"':
src++;
continue;
}
}
*dst++ = *src++;
}
*dst = '\0';
return dst;
}
/* =========================================================================
* Finds and extracts a header line from a full multi-lined header. All
* unfolding (removing newlines) is done before header line is returned.
*
* NOTE: The user of this function is responsible for freeing the
* returned string.
*
* Args: pFullHeader [IN] Pointer to a full RFC822 header, including newlines
* pLinePrefix [IN] Prefix of header line to extract
*
* Returns: Extracted header line string; dynamically allocated.
*/
char *RFC822_ExtractHeader(const char *pFullHeader, const char *pLinePrefix)
{
const char *kNewline = "\r\n";
const unsigned short kNewlineLen = 2;
const unsigned short nPreLen = strlen(pLinePrefix);
char *pStart, *pEnd, *pBuf, *pPos, *pRetBuf;
if (nPreLen < 1)
return (nil);
pStart = (char*) pFullHeader;
// Find first 'line' which matches prefix
while ((pStart) && (strnicmp(pStart, pLinePrefix, nPreLen) != 0)) {
pStart = strstr(pStart, kNewline);
if (pStart)
pStart += kNewlineLen;
}
if (!pStart)
return nil; // Not found
// Find the end of this header line
for (pEnd = strstr(pStart, kNewline); (pEnd != nil); pEnd = strstr(pEnd, kNewline)) {
pPos = pEnd + kNewlineLen;
if ((*pPos == ' ') || (*pPos == '\t')) // Does header line continue on next line?
pEnd = pPos;
else
break;
}
// If we ran off the end of the string, then the end is the last char in the string
if (pEnd == nil)
pEnd = strchr(pStart, '\0');
pBuf = pRetBuf = NewPtr(pEnd - pStart + 1); // Max length of output string
for (pPos = pStart; pPos < pEnd; pPos++) {
if (strncmp(pPos, kNewline, kNewlineLen) == 0) // We're at a newline
pPos += kNewlineLen; // Skip over newline
*pBuf++ = *pPos;
}
*pBuf = '\0';
return pRetBuf;
}